package com.googlecode.cswish.util.bean;

import com.googlecode.cswish.model.ModelInfo;
import com.googlecode.cswish.model.PropertyInfo;
import com.googlecode.cswish.util.ClassUtil;

public class ScannerContext {
	
	private ScannerContext parentContext;
	
	private ModelInfo modelInfo;

	private Object srcModel;

	private String parentPath;

	private PropertyInfo propertyDescriptor;
	
	private int subscript = -1;		// the subscript of the collection, only valid when parent context is collection

	private boolean caculatedSrc;

	private Object srcPropertyValue;

	private Object destModel;

	private boolean caculatedDest;

	private Object destPropertyValue;
	
	private int deep;
	
	public ScannerContext(ScannerContext parentContext) {
		this.parentContext = parentContext;
		if (parentContext != null) {
			this.deep = parentContext.deep + 1;
		}
	}
	
	public ScannerContext getParentContext() {
		return parentContext;
	}

	public void setParentContext(ScannerContext parentContext) {
		this.parentContext = parentContext;
	}
	

	public ModelInfo getModelInfo() {
		return modelInfo;
	}

	public void setModelInfo(ModelInfo modelInfo) {
		this.modelInfo = modelInfo;
	}

	public Object getSrcModel() {
		return srcModel;
	}

	public void setSrcModel(Object parent) {
		this.srcModel = parent;
	}

	public String getParentPath() {
		return parentPath;
	}

	public void setParentPath(String parentPath) {
		this.parentPath = parentPath;
	}

	public String getChildPath() {	// boolean useExactPath
		return parentPath == null ? propertyDescriptor.getName() : parentPath + '.'
				+ propertyDescriptor.getName();
	}

	public PropertyInfo getPropertyDescriptor() {
		return propertyDescriptor;
	}

	public void setPropertyDescriptor(PropertyInfo propertyDescriptor) {
		this.caculatedSrc = false;
		this.caculatedDest = false;
		this.propertyDescriptor = propertyDescriptor;
	}

	public Object getSrcPropertyValue() {
		if (caculatedSrc) {
			return srcPropertyValue;
		}

		caculatedSrc = true;
		srcPropertyValue = propertyDescriptor.getValue(srcModel, modelInfo);
		return srcPropertyValue;
	}

	public void setSrcPropertyValue(Object propertyValue) {
		propertyDescriptor.setValue(srcModel, propertyValue, modelInfo);
		
		this.srcPropertyValue = propertyValue;
		caculatedSrc = true;
	}
	
	public void setSrcPropertyValueWithoutModify(Object propertyValue) {
		this.srcPropertyValue = propertyValue;
		caculatedSrc = true;
	}

	public Object getDestModel() {
		return destModel;
	}

	public void setDestModel(Object dest) {
		this.destModel = dest;
	}

	public Object getDestPropertyValue() {
		if (caculatedDest) {
			return destPropertyValue;
		}

		caculatedDest = true;
		destPropertyValue = propertyDescriptor.getValue(destModel, modelInfo);
		return destPropertyValue;
	}

	public void setDestPropertyValue(Object propertyValue) {
		propertyDescriptor.setValue(destModel, propertyValue, modelInfo);
		
		this.destPropertyValue = propertyValue;
		caculatedDest = true;
	}
	
	public void setDestPropertyValueWithoutModify(Object propertyValue) {
		this.destPropertyValue = propertyValue;
		caculatedDest = true;
	}

	public boolean isSimpleObj() {
		return propertyDescriptor.isSimpleObj();
	}

	public boolean isCollection() {
		return subscript == -1 && ClassUtil.isCollection(propertyDescriptor.getReadMethod().getReturnType());
	}

	public int getSubscript() {
		return subscript;
	}

	public void setSubscript(int subscript) {
		this.subscript = subscript;
	}
	
	public void setDeep(int deep) {
		this.deep = deep;
	}

	public int getDeep() {
		return deep;
	}

	public String toString() {
		return parentPath == null ? propertyDescriptor.getName() : (
				parentPath == null ? propertyDescriptor.getName() : parentPath + '.' + propertyDescriptor.getName());
	}
}